package com.northwind.aspect;

import com.northwind.entity.Admin;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;


import javax.annotation.Resource;
import javax.servlet.http.HttpSession;

@Configuration
@Aspect

public class CacheAspect {
    @Resource
    RedisTemplate redisTemplate;

    @Resource
    StringRedisTemplate stringRedisTemplate;

    @Resource
    HttpSession session;


    /**
     * 优化
     * KEY:string
     * VALUE:Hash<key,value>
     *
     * KEY:类的权全限定名
     * key:方法名+实参
     * value:数据
    * */

    //@Around("execution(* com.northwind.serviceImpl.*.query*(..))")
    @Around("@annotation(com.northwind.annotation.AddCache)")
    public Object addCache(ProceedingJoinPoint joinPoint)  {
        /** 缓存逻辑处理
          Redis结构:  key：类的全限定名+方法名+实参   value：查询的数据结果
        判断切到的方法有没有缓存,没有先放行，查询数据库，返回结果加入缓存
                        有 取出缓存返回结果*/

        System.out.println("======进入CacheAspect环绕通知======");

        //解决乱码
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        //字符串拼接
        StringBuilder stringBuilder = new StringBuilder();
        //类的全限定名,做KEY
        String className = joinPoint.getTarget().getClass().getName();
        //stringBuilder.append(className);
        //方法名
        String methodName = joinPoint.getSignature().getName();
        stringBuilder.append(methodName);
        //获取参数的数组
        Object[] args = joinPoint.getArgs();
        for (Object arg : args) {
            stringBuilder.append(arg);
        }


        //获取拼接好的key,方法名+实参
        String key = stringBuilder.toString();
        //获取String类型的操作
        HashOperations hashOperations = redisTemplate.opsForHash();
        //判断数据库中是否有这个KEY下的key(缓存是否存在)
        Boolean aBoolean = hashOperations.hasKey(className,key);
        Object result = null;
        if (aBoolean) {
            //有
            System.out.println("redis返回数据");
            result = hashOperations.get(className,key);
        }else {
            //无
            //放行目标方法
            try {
                result = joinPoint.proceed();
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
            System.out.println("加入redis");
            hashOperations.put(className,key,result);
        }
        return result;
    }


    //清除缓存
    @AfterReturning("@annotation(com.northwind.annotation.DelCache)")//返回通知
    public void delCache(JoinPoint joinPoint) {

        //类的全限定名
        String className = joinPoint.getTarget().getClass().getName();
        stringRedisTemplate.delete(className);
    }

    //登录用redis
    @Around("@annotation(com.northwind.annotation.LoginCache)")
    public Object LoginCache(ProceedingJoinPoint joinPoint){
        //解决乱码
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        //字符串拼接
        StringBuilder stringBuilder = new StringBuilder();
        //类的全限定名,做KEY
        String className = joinPoint.getTarget().getClass().getName();
        //stringBuilder.append(className);
        //方法名
        String methodName = joinPoint.getSignature().getName();
        stringBuilder.append(methodName);
        //获取参数的数组
        Object[] args = joinPoint.getArgs();
        stringBuilder.append(args[0]);
        //Admin(admin_id=null, username=DeepHunter, password=123456, salt=null, status=null)

        ///获取拼接好的key,方法名+实参
        String key = stringBuilder.toString();
        //获取String类型的操作
        HashOperations hashOperations = redisTemplate.opsForHash();
        //判断数据库中是否有这个KEY下的key(缓存是否存在)
        Boolean aBoolean = hashOperations.hasKey(className,key);
        Object result = null;
        if (aBoolean) {
            //有
            System.out.println("redis返回数据");
            result = hashOperations.get(className,key);
            Admin admin = (Admin) args[0];
            //System.out.println(admin);
            //注意要重新添加Session，否则Session超时后会导致session无法正常挂载
            session.setAttribute("admin",admin);

        }else {
            //无
            //放行目标方法
            try {
                result = joinPoint.proceed();
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
            System.out.println("加入redis");
            hashOperations.put(className,key,result);
        }
        return result;
    }


}
